package org.apache.catalina.connector.http;

import org.apache.catalina.*;
import org.apache.catalina.net.DefaultServerSocketFactory;
import org.apache.catalina.net.ServerSocketFactory;
import org.apache.catalina.util.LifecycleSupport;
import org.apache.catalina.util.StringManager;

import java.io.IOException;
import java.net.BindException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.UnknownHostException;

/**
 * 2020/7/22 : 10:30
 */
public class HttpConnector implements Connector, Lifecycle, Runnable {

    private boolean initialized=false;
    private boolean started=false;
    private String threadName;
    private ServerSocket serverSocket;
    private ServerSocketFactory factory;
    private String address;
    private int port = 8080;
    private int acceptCount = 10;

    private StringManager sm = StringManager.getManager(Constants.Package);

    protected Container container;
    protected LifecycleSupport lifecycle=new LifecycleSupport(this);


    @Override
    public void run() {

    }

    @Override
    public void setContainer(Container container) {
        this.container = container;
    }

    @Override
    public void initialize() throws LifecycleException {
        if (initialized) {
            throw new LifecycleException(sm.getString("httpConnector.alreadyInitialized"))
        }
        this.initialized = true;
        Exception eThrow = null;
        try {
            serverSocket = open();
        } catch (BindException e) {
            e.printStackTrace();
        }
        if (eThrow != null) {
            throw new LifecycleException(threadName + ".open", eThrow);
        }
    }

    @Override
    public void start() throws LifecycleException {
        if (started) {
            throw new LifecycleException
                    (sm.getString("httpConnector.alreadyStarted"));
        }
        threadName="HttpConnector["+port+"]";
        lifecycle.fireLifecycleEvent(START_EVENT,null);
        started=true;
        threadStart();
        
    }

    /**
     * 启动线程
     */
    private void threadStart() {
        
        
    }

    @Override
    public void stop() {

    }

    /**
     * 为当前连接器打开链接，如果指定了ip，则打开指定ip；
     * 否则打开所有地址
     *
     * @return
     */
    private ServerSocket open() throws BindException {
        ServerSocketFactory factory = getFactory();
        if (address == null) {
            log(sm.getString("httpConnector.allAddress"));
            try {
                return factory.createSocket(port, acceptCount);
            } catch (BindException be) {
                throw new BindException(be.getMessage() + ":" + port);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        try {
            InetAddress is = InetAddress.getByName(address);
            log(sm.getString("httpConnector.anAddress", address));
            try {
                return (factory.createSocket(port, acceptCount, is));
            } catch (BindException be) {
                throw new BindException(be.getMessage() + ":" + address +
                        ":" + port);
            } catch (IOException e) {
                e.printStackTrace();
            }
        } catch (Exception e){
            log(sm.getString("httpConnector.noAddress", address));
            try {
                return (factory.createSocket(port,acceptCount));
            } catch (IOException ex) {
                throw new BindException(e.getMessage() + ":" + port);
            }
        }
    }

    /**
     * 创建ServerSocketFactory
     *
     * @return
     */
    private ServerSocketFactory getFactory() {
        if (this.factory == null) {
            synchronized (this) {
                this.factory = new DefaultServerSocketFactory();
            }
        }
        return this.factory;
    }

    private void log(String message) {
        Logger logger = container.getLogger();
        String localName = threadName;
        if (localName == null)
            localName = "HttpConnector";
        if (logger != null)
            logger.log(localName + " " + message);
        else
            System.out.println(localName + " " + message);

    }
}
